package com.baofu.trade.service.impl;

import com.baofu.trade.cache.MarketDataCache;
import com.baofu.trade.exception.MarketDataException;
import com.baofu.trade.indicator.TechnicalIndicator;
import com.baofu.trade.model.KlineData;
import com.baofu.trade.model.PriceAnalysis;
import com.baofu.trade.model.indicator.EMAResult;
import com.baofu.trade.model.indicator.MACDResult;
import com.baofu.trade.model.PriceRange;
import com.baofu.trade.model.PriceBreakoutAnalysis;
import com.baofu.trade.service.MarketDataService;
import lombok.extern.slf4j.Slf4j;
import org.knowm.xchange.Exchange;
import org.knowm.xchange.binance.dto.marketdata.KlineInterval;
import org.knowm.xchange.currency.CurrencyPair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.client.BufferingClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class BinanceMarketDataServiceImpl implements MarketDataService {

    @Autowired
    private Exchange exchange;
    
    private final RestTemplate restTemplate;
    private final String BINANCE_API_URL = "https://api.binance.com";
    private final String BINANCE_FUTURES_API_URL = "https://fapi.binance.com";
    private static final ZoneId SHANGHAI_ZONE = ZoneId.of("Asia/Shanghai");
    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    
    @Autowired
    private TechnicalIndicator technicalIndicator;
    
    @Autowired
    private MarketDataCache marketDataCache;
    
    public BinanceMarketDataServiceImpl() {
        // 创建代理配置
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        
        // 设置代理
        Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 7890));
        factory.setProxy(proxy);
        
        // 设置超时
        factory.setConnectTimeout(60000);
        factory.setReadTimeout(60000);
        
        // 创建带有重试机制的RestTemplate
        this.restTemplate = new RestTemplate(factory);
        
        // 添加试拦截器
        this.restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(factory));
        this.restTemplate.setInterceptors(Collections.singletonList((request, body, execution) -> {
            int maxRetries = 3;
            int retryCount = 0;
            while (retryCount < maxRetries) {
                try {
                    return execution.execute(request, body);
                } catch (Exception e) {
                    retryCount++;
                    if (retryCount == maxRetries) {
                        throw e;
                    }
                    log.warn("请求失败，正在进行第{}次重试", retryCount);
                    try {
                        Thread.sleep(1000 * retryCount); // 重试间隔递增
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                        throw e;
                    }
                }
            }
            throw new RuntimeException("重试次数已达上限");
        }));
    }

    /**
     * 将交易对字符串转换为CurrencyPair对象
     * 例如：BTCUSDT -> BTC/USDT
     */
    private CurrencyPair parseCurrencyPair(String symbol) {
        if (symbol == null || symbol.length() < 2) {
            throw new IllegalArgumentException("Invalid symbol: " + symbol);
        }
        
        // 对于USDT结尾的交易对
        if (symbol.endsWith("USDT")) {
            String baseCurrency = symbol.substring(0, symbol.length() - 4);
            return new CurrencyPair(baseCurrency, "USDT");
        }
        
        // 如果有其他类型的交易对，可以在这里添加处理逻辑
        throw new IllegalArgumentException("Unsupported symbol format: " + symbol);
    }

    /**
     * 将字符串时间间隔转换为KlineInterval枚举
     */
    private KlineInterval parseInterval(String interval) {
        return switch (interval.toLowerCase()) {
            case "1m" -> KlineInterval.m1;
            case "3m" -> KlineInterval.m3;
            case "5m" -> KlineInterval.m5;
            case "15m" -> KlineInterval.m15;
            case "30m" -> KlineInterval.m30;
            case "1h" -> KlineInterval.h1;
            case "2h" -> KlineInterval.h2;
            case "4h" -> KlineInterval.h4;
            case "6h" -> KlineInterval.h6;
            case "8h" -> KlineInterval.h8;
            case "12h" -> KlineInterval.h12;
            case "1d" -> KlineInterval.d1;
            case "3d" -> KlineInterval.d3;
            case "1w" -> KlineInterval.w1;
            case "1M" -> KlineInterval.M1;
            default -> throw new IllegalArgumentException("Unsupported interval: " + interval);
        };
    }

    @Override
    public List<KlineData> getKlineData(String symbol, String interval, Integer limit) {
        try {
            String cacheKey = String.format("%s-%s-%d", symbol, interval, limit);
            return marketDataCache.getOrLoad(cacheKey, key -> fetchKlineDataFromExchange(symbol, interval, limit));
        } catch (Exception e) {
            log.error("获取K线数据失败: symbol={}, interval={}", symbol, interval, e);
            throw new MarketDataException("获取K线数据失败: " + e.getMessage(), e);
        }
    }

    private List<KlineData> fetchKlineDataFromExchange(String symbol, String interval, Integer limit) {
        try {
            // 构建请求URL
            String url = String.format("%s/api/v3/klines?symbol=%s&interval=%s&limit=%d",
                BINANCE_API_URL, symbol, interval, limit);
            
            // 发送请求并获取响应
            Object[][] rawKlines = restTemplate.getForObject(url, Object[][].class);
            
            if (rawKlines == null) {
                throw new MarketDataException("获取K线数据失败: 响应为空");
            }
            
            // 转换数据
            List<KlineData> klineDataList = new ArrayList<>();
            for (Object[] kline : rawKlines) {
                KlineData data = new KlineData();
                
                // 设置时间
                data.setOpenTime(Long.parseLong(kline[0].toString()));
                data.setCloseTime(Long.parseLong(kline[6].toString()));
                
                // 设置价格数据
                data.setOpen(kline[1].toString());
                data.setHigh(kline[2].toString());
                data.setLow(kline[3].toString());
                data.setClose(kline[4].toString());
                
                // 设置成交量数据
                data.setVolume(kline[5].toString());
                data.setQuoteAssetVolume(kline[7].toString());
                
                // 设置其他数据
                data.setNumberOfTrades(Long.parseLong(kline[8].toString()));
                data.setTakerBuyBaseAssetVolume(kline[9].toString());
                data.setTakerBuyQuoteAssetVolume(kline[10].toString());
                
                klineDataList.add(data);
            }
            Collections.reverse(klineDataList);
            return klineDataList;
                
        } catch (Exception e) {
            throw new MarketDataException("从交易所获取K线数据失败: " + e.getMessage(), e);
        }
    }

    @Override
    public String getLatestPrice(String symbol) {
        try {
            // 构建请求URL
            String url = String.format("%s/api/v3/ticker/price?symbol=%s", 
                BINANCE_API_URL, symbol);
            
            // 发送请求并获取响应
            Map<String, String> response = restTemplate.getForObject(url, Map.class);
            
            if (response == null || !response.containsKey("price")) {
                throw new RuntimeException("获取最新价格失败: 响应数据格式错误");
            }
            
            return response.get("price");
                
        } catch (Exception e) {
            log.error("获取最新价格失败: symbol={}", symbol, e);
            throw new RuntimeException("获取最新价格失败: " + e.getMessage());
        }
    }

    @Override
    public Map<String, String> getHighLowPrice(String symbol, String interval, Integer limit) {
        try {
            List<KlineData> klineDataList = getKlineData(symbol, interval, limit);
            
            if (klineDataList.isEmpty()) {
                throw new RuntimeException("获取K线数据为空");
            }

            // 使用BigDecimal来确保精确计算
            BigDecimal highestPrice = new BigDecimal(klineDataList.get(0).getHigh());
            BigDecimal lowestPrice = new BigDecimal(klineDataList.get(0).getLow());
            String highestTime = klineDataList.get(0).getOpenTimeBeijing();
            String lowestTime = klineDataList.get(0).getOpenTimeBeijing();

            // 遍历所有K线数据找出最高价和最低价
            for (KlineData kline : klineDataList) {
                BigDecimal high = new BigDecimal(kline.getHigh());
                BigDecimal low = new BigDecimal(kline.getLow());

                // 更新最高价
                if (high.compareTo(highestPrice) > 0) {
                    highestPrice = high;
                    highestTime = kline.getOpenTimeBeijing();
                }

                // 更新最低价
                if (low.compareTo(lowestPrice) < 0) {
                    lowestPrice = low;
                    lowestTime = kline.getOpenTimeBeijing();
                }
            }

            // 构建返回结果
            Map<String, String> result = new HashMap<>();
            result.put("最高价", highestPrice.setScale(2, RoundingMode.HALF_UP).toPlainString());
            result.put("最低价时间", highestTime);
            result.put("最低价", lowestPrice.setScale(2, RoundingMode.HALF_UP).toPlainString());
            result.put("最低价时间", lowestTime);
            result.put("价格波动", highestPrice.subtract(lowestPrice).setScale(2, RoundingMode.HALF_UP).toPlainString());
            result.put("波动比例", highestPrice.subtract(lowestPrice)
                .divide(lowestPrice, 4, RoundingMode.HALF_UP)
                .multiply(new BigDecimal("100"))
                .setScale(2, RoundingMode.HALF_UP).toPlainString() + "%");

            return result;

        } catch (Exception e) {
            log.error("获取最高最低价格失败: symbol={}, interval={}, limit={}", symbol, interval, limit, e);
            throw new RuntimeException("获取最高最低价格失败: " + e.getMessage());
        }
    }

    @Override
    public Map<String, String> getKeyLevels(String symbol, String interval, Integer limit) {
        try {
            // 1. 获取K线数据（直接调用fetchKlineDataFromExchange避免缓存循环）
            List<KlineData> klineDataList = fetchKlineDataFromExchange(symbol, interval, limit);
            
            // 2. 创建价格分析对象
            PriceAnalysis analysis = new PriceAnalysis();
            
            // 3. 设置基本数据
            analysis.setCurrentPrice(new BigDecimal(getLatestPrice(symbol)));
            setPriceRange(analysis, klineDataList);
            
            // 4. 计算技术指标
            calculateTechnicalIndicators(analysis, klineDataList);
            
            // 5. 生成位置分析
            analysis.setPositionAnalysis(generatePositionAnalysis(analysis));
            
            // 6. 转换为Map返回
            return analysis.toMap();
            
        } catch (Exception e) {
            log.error("计算关键位失败: symbol={}, interval={}, limit={}", symbol, interval, limit, e);
            throw new MarketDataException("计算关键位失败: " + e.getMessage(), e);
        }
    }

    private void setPriceRange(PriceAnalysis analysis, List<KlineData> klineDataList) {
        BigDecimal highestPrice = new BigDecimal(klineDataList.get(0).getHigh());
        BigDecimal lowestPrice = new BigDecimal(klineDataList.get(0).getLow());
        
        for (KlineData kline : klineDataList) {
            BigDecimal high = new BigDecimal(kline.getHigh());
            BigDecimal low = new BigDecimal(kline.getLow());
            if (high.compareTo(highestPrice) > 0) highestPrice = high;
            if (low.compareTo(lowestPrice) < 0) lowestPrice = low;
        }
        
        analysis.setHighestPrice(highestPrice);
        analysis.setLowestPrice(lowestPrice);
    }
    
    private void calculateTechnicalIndicators(PriceAnalysis analysis, List<KlineData> klineDataList) {
        // 准备收盘价列表
        List<BigDecimal> prices = new ArrayList<>();
        for (KlineData kline : klineDataList) {
            prices.add(new BigDecimal(kline.getClose()));
        }
        // 计算EMA
        List<EMAResult> emaResults = new ArrayList<>();
        emaResults.add(createEMAResult(5, "短期趋势", technicalIndicator.calculateEMA(prices, 5)));
        emaResults.add(createEMAResult(10, "短中期趋势", technicalIndicator.calculateEMA(prices, 10)));
        emaResults.add(createEMAResult(20, "中期趋势", technicalIndicator.calculateEMA(prices, 20)));
        emaResults.add(createEMAResult(30, "中长期趋势", technicalIndicator.calculateEMA(prices, 30)));
        analysis.setEmaResults(emaResults);
        
        // 计算布林带
        analysis.setBollingerBands(technicalIndicator.calculateBollingerBands(prices, 20, 2));
        
        // 计算斐波那契水
        analysis.setFibonacciLevels(technicalIndicator.calculateFibonacciLevels(
            analysis.getHighestPrice(), 
            analysis.getLowestPrice()
        ));
    }
    
    private EMAResult createEMAResult(int period, String description, BigDecimal value) {
        EMAResult result = new EMAResult();
        result.setPeriod(period);
        result.setDescription(description);
        result.setValue(value);
        return result;
    }
    
    private String generatePositionAnalysis(PriceAnalysis analysis) {
        List<String> positions = new ArrayList<>();
        
        // 布林带位置分析
        if (analysis.getCurrentPrice().compareTo(analysis.getBollingerBands().getUpper()) > 0) {
            positions.add("当前价格位布林上轨之上，可能存在超买，注意回调风险");
        } else if (analysis.getCurrentPrice().compareTo(analysis.getBollingerBands().getLower()) < 0) {
            positions.add("当前价格位于布林下轨之下，可能存在超卖，可以考虑逢低买入");
        } else {
            positions.add("当前价格位于布林带中轨区域，波动相对正常，可以观察趋势后操作");
        }
        
        // 价格区间位置分析
        BigDecimal range = analysis.getHighestPrice().subtract(analysis.getLowestPrice());
        BigDecimal position = analysis.getCurrentPrice().subtract(analysis.getLowestPrice())
            .divide(range, 4, RoundingMode.HALF_UP);
        positions.add(String.format("当前价格位于近期高低点之间的%.2f%%位置", 
            position.multiply(new BigDecimal("100"))));
        
        // 趋势判断
        if (position.compareTo(new BigDecimal("0.7")) > 0) {
            positions.add("价格近高位，注意防守");
        } else if (position.compareTo(new BigDecimal("0.3")) < 0) {
            positions.add("价格接近低位，可以考虑建仓");
        }
        
        return String.join("；", positions);
    }

    /**
     * 获取合约K线数据
     * 
     * 功能明：
     * - 获取指定交易对的期货K线数据
     * - 支持自定义时间范围和数据条数
     * - 数据包含开盘价、最高价、最低价、收盘价、交易量等信息
     * 
     * 请求示例：
     * GET /api/futures/klines?symbol=BTCUSDT&interval=1h&startTime=1609459200000&endTime=1609545600000&limit=100
     *
     * @param symbol   交易对符号（必填）
     *                 - 格式：基础货+计价货币，例如：BTCUSDT, ETHUSDT
     * @param interval K线时间周期（必填）
     *                 - 1m：1分钟
     *                 - 5m：5分钟
     *                 - 15m：15分钟
     *                 - 30m：30分钟
     *                 - 1h：1小时
     *                 - 4h：4小时
     *                 - 1d：1天
     *                 - 1w：1周
     * @param startTime 开始时间（选填）
     *                  - 毫秒级时间戳
     * @param endTime   结束时间（选填）
     *                  - 毫秒级时间戳
     * @param limit     获取K线数量（选填）
     *                  - 默认值：500
     *                  - 有效范围：[1-1000]
     * @return K线数据列表，按时间升序排列
     */
    @Override
    public List<KlineData> getFuturesKlineData(String symbol, String interval, Long startTime, Long endTime, Integer limit) {
        try {
            // 构建请求URL，包含必要的参数
            StringBuilder urlBuilder = new StringBuilder(String.format("%s/fapi/v1/klines?symbol=%s&interval=%s", 
                BINANCE_FUTURES_API_URL, symbol, interval));
            
            // 如果提供了开始时间，则添加到URL
            if (startTime != null) {
                urlBuilder.append("&startTime=").append(startTime);
            }
            // 如果提供了结束时间，则添加到URL
            if (endTime != null) {
                urlBuilder.append("&endTime=").append(endTime);
            }
            // 如果提供了限制数量，则添加到URL
            if (limit != null) {
                urlBuilder.append("&limit=").append(limit);
            }
            
            // 完整的请求URL
            String url = urlBuilder.toString();
            
            // 发送HTTP GET请求并获取响应
            Object[][] rawKlines = restTemplate.getForObject(url, Object[][].class);
            
            // 如果响应为空，抛出异常
            if (rawKlines == null) {
                throw new RuntimeException("获取合约K线数据失败: 响应为空");
            }
            
            // 将响应数据转换为KlineData对象列表
            return Arrays.stream(rawKlines)
                .map(kline -> {
                    KlineData data = new KlineData();
                    data.setOpenTime(Long.parseLong(kline[0].toString())); // 开盘时间
                    data.setOpen(kline[1].toString()); // 开价
                    data.setHigh(kline[2].toString()); // 最高价
                    data.setLow(kline[3].toString()); // 最低价
                    data.setClose(kline[4].toString()); // 收盘价
                    data.setVolume(kline[5].toString()); // 交易量
                    data.setCloseTime(Long.parseLong(kline[6].toString())); // 收盘时间
                    data.setQuoteAssetVolume(kline[7].toString()); // 成交额
                    data.setNumberOfTrades(Long.parseLong(kline[8].toString())); // 成交笔数
                    data.setTakerBuyBaseAssetVolume(kline[9].toString()); // 主动买入成交量
                    data.setTakerBuyQuoteAssetVolume(kline[10].toString()); // 主动买入成交额
                    return data;
                })
                .collect(Collectors.toList());
                
        } catch (Exception e) {
            log.error("获取合约K线数据失败: symbol={}, interval={}", symbol, interval, e);
            throw new RuntimeException("获取合约K线数据失败: " + e.getMessage());
        }
    }

    @Override
    public MACDResult getMACD(String symbol, String interval, Integer limit) {
        try {
            // 1. 获取K线数据 - 直接调用fetchKlineDataFromExchange避免使用缓存
            List<KlineData> klineDataList = fetchKlineDataFromExchange(symbol, interval, limit);
            
            // 2. 提取收盘价序列
            List<BigDecimal> prices = klineDataList.stream()
                .map(kline -> new BigDecimal(kline.getClose()))
                .collect(Collectors.toList());
            
            // 3. 计算MACD
            return technicalIndicator.calculateMACD(prices);
            
        } catch (Exception e) {
            log.error("计算MACD失败: symbol={}, interval={}", symbol, interval, e);
            throw new MarketDataException("计算MACD失败: " + e.getMessage(), e);
        }
    }

    @Override
    public List<KlineData> getHistoricalKlineData(String symbol, String interval, 
            LocalDateTime startTime, LocalDateTime endTime, Integer limit) {
        try {
            // 获取当前时间
            LocalDateTime now = LocalDateTime.now();
            
            // 如果结束时间超过当前时间，使用当前时间作为结束时间
            LocalDateTime actualEndTime = endTime.isAfter(now) ? now : endTime;
            
            // 根据时间间隔计算所需的数据数量
            long dataPoints = calculateDataPoints(interval, startTime, actualEndTime);
            
            // 如果计算出的数据点数量超过1500，抛出异常
            if (dataPoints > 1500) {
                throw new IllegalArgumentException(
                    String.format("时间范围过大，当前时间范围包含 %d 个数据点，币安最多支持查询1500个数据点", dataPoints));
            }
            
            // 计算实际需要的数据点数量
            int actualLimit = calculateActualLimit(limit, dataPoints);
            
            // 转换为时间戳
            ZoneId zoneId = ZoneId.systemDefault();
            long startTimestamp = startTime.atZone(zoneId).toInstant().toEpochMilli();
            long endTimestamp = actualEndTime.atZone(zoneId).toInstant().toEpochMilli();
            
            // 构建缓存key
            String cacheKey = String.format("%s-%s-%d-%d-%d", symbol, interval, startTimestamp, endTimestamp, actualLimit);
            
            return marketDataCache.getOrLoad(cacheKey, key -> fetchHistoricalKlineData(
                symbol, interval, startTimestamp, endTimestamp, actualLimit));
            
        } catch (Exception e) {
            log.error("获取历史K线数据失败", e);
            throw new MarketDataException("获取历史K线数据失败: " + e.getMessage());
        }
    }

    private long calculateDataPoints(String interval, LocalDateTime startTime, LocalDateTime endTime) {
        switch (interval.toLowerCase()) {
            case "1m":
                return ChronoUnit.MINUTES.between(startTime, endTime);
            case "3m":
                return ChronoUnit.MINUTES.between(startTime, endTime) / 3;
            case "5m":
                return ChronoUnit.MINUTES.between(startTime, endTime) / 5;
            case "15m":
                return ChronoUnit.MINUTES.between(startTime, endTime) / 15;
            case "30m":
                return ChronoUnit.MINUTES.between(startTime, endTime) / 30;
            case "1h":
                return ChronoUnit.HOURS.between(startTime, endTime);
            case "2h":
                return ChronoUnit.HOURS.between(startTime, endTime) / 2;
            case "4h":
                return ChronoUnit.HOURS.between(startTime, endTime) / 4;
            case "6h":
                return ChronoUnit.HOURS.between(startTime, endTime) / 6;
            case "8h":
                return ChronoUnit.HOURS.between(startTime, endTime) / 8;
            case "12h":
                return ChronoUnit.HOURS.between(startTime, endTime) / 12;
            case "1d":
                return ChronoUnit.DAYS.between(startTime, endTime);
            case "3d":
                return ChronoUnit.DAYS.between(startTime, endTime) / 3;
            case "1w":
                return ChronoUnit.WEEKS.between(startTime, endTime);
            case "1M":
                return ChronoUnit.MONTHS.between(startTime, endTime);
            default:
                throw new IllegalArgumentException("不支持的时间间隔: " + interval);
        }
    }

    private int calculateActualLimit(Integer limit, long dataPoints) {
        // 如果提供了limit参数且小于计算出的数据点数量，使用limit参数
        // 否使用计算出的数据点数量
        int actualLimit = (limit != null && limit < dataPoints) ? limit : (int) dataPoints;
        
        // 确保actualLimit至少为1
        return Math.max(1, actualLimit);
    }

    private List<KlineData> fetchHistoricalKlineData(String symbol, String interval, 
            long startTime, long endTime, int limit) {
        try {
            // 构建请求URL
            String url = String.format("%s/fapi/v1/klines?symbol=%s&interval=%s&startTime=%d&endTime=%d&limit=%d",
                BINANCE_FUTURES_API_URL, symbol, interval, startTime, endTime, limit);
            
            log.debug("请求历史K线数据: {}", url);
            
            // 发送请求并获取响应
            Object[][] rawKlines = restTemplate.getForObject(url, Object[][].class);
            
            if (rawKlines == null || rawKlines.length == 0) {
                return Collections.emptyList();
            }
            
            // 转换数据
            List<KlineData> klineDataList = Arrays.stream(rawKlines)
                .map(this::convertToKlineData)
                .collect(Collectors.toList());
            
            // 按开盘时间排序
            klineDataList.sort(Comparator.comparing(KlineData::getOpenTime));
            
            return klineDataList;
            
        } catch (Exception e) {
            log.error("获取历史K线数据失败: symbol={}, interval={}, startTime={}, endTime={}, limit={}",
                symbol, interval, startTime, endTime, limit, e);
            throw new MarketDataException("获取历史K线数据失败: " + e.getMessage());
        }
    }

    private KlineData convertToKlineData(Object[] kline) {
        KlineData data = new KlineData();
        data.setOpenTime(Long.parseLong(kline[0].toString()));
        data.setOpen(kline[1].toString());
        data.setHigh(kline[2].toString());
        data.setLow(kline[3].toString());
        data.setClose(kline[4].toString());
        data.setVolume(kline[5].toString());
        data.setCloseTime(Long.parseLong(kline[6].toString()));
        data.setQuoteAssetVolume(kline[7].toString());
        data.setNumberOfTrades(Long.parseLong(kline[8].toString()));
        data.setTakerBuyBaseAssetVolume(kline[9].toString());
        data.setTakerBuyQuoteAssetVolume(kline[10].toString());
        return data;
    }

    @Override
    public PriceRange getPriceRange(String symbol, String interval, int days) {
        try {
            // 计算时间范围：从当前日期往前推
            LocalDateTime now = LocalDateTime.now()
                .withHour(8).withMinute(0).withSecond(0).withNano(0);  // 调整到早上8点
            
            // 计算结束时间和开始时间
            LocalDateTime endTime = now.withDayOfMonth(15);    // 本月15号
            LocalDateTime startTime = now.withDayOfMonth(1);   // 本月1号
            
            log.info("分析价格区间: {} 到 {}", 
                startTime.format(DATE_FORMATTER), 
                endTime.format(DATE_FORMATTER));
            
            // 获取历史K线数据
            List<KlineData> klineDataList = getHistoricalKlineData(symbol, interval, startTime, endTime, null);
            
            // 初始化最高价和最低价
            BigDecimal highPrice = BigDecimal.ZERO;
            BigDecimal lowPrice = new BigDecimal("999999999");
            LocalDateTime highTime = null;
            LocalDateTime lowTime = null;
            
            // 遍历K线数据找出最高价和最低价
            for (KlineData kline : klineDataList) {
                BigDecimal high = new BigDecimal(kline.getHigh());
                BigDecimal low = new BigDecimal(kline.getLow());
                
                if (high.compareTo(highPrice) > 0) {
                    highPrice = high;
                    highTime = LocalDateTime.ofInstant(
                        java.time.Instant.ofEpochMilli(kline.getOpenTime()), 
                        ZoneId.systemDefault()
                    );
                }
                
                if (low.compareTo(lowPrice) < 0) {
                    lowPrice = low;
                    lowTime = LocalDateTime.ofInstant(
                        java.time.Instant.ofEpochMilli(kline.getOpenTime()), 
                        ZoneId.systemDefault()
                    );
                }
            }
            
            // 计算波动幅度
            BigDecimal fluctuationRate = highPrice.subtract(lowPrice)
                .divide(lowPrice, 4, RoundingMode.HALF_UP)
                .multiply(new BigDecimal("100"));
            
            // 判断是否超过5%
            boolean exceeds5Percent = fluctuationRate.compareTo(new BigDecimal("5")) >= 0;
            
            // 构建返回结果
            return PriceRange.builder()
                .timeRange(String.format("%s 到 %s", 
                    startTime.format(DATE_FORMATTER),
                    endTime.format(DATE_FORMATTER)))
                .lowPrice(lowPrice.toString())
                .highPrice(highPrice.toString())
                .lowPriceTime(lowTime != null ? lowTime.format(DATE_FORMATTER) : null)
                .highPriceTime(highTime != null ? highTime.format(DATE_FORMATTER) : null)
                .fluctuationRate(String.format("%.2f%%", fluctuationRate))
                .exceeds5Percent(exceeds5Percent)
                .build();
            
        } catch (Exception e) {
            log.error("获取价格极值失败: symbol={}, interval={}, days={}", symbol, interval, days, e);
            throw new MarketDataException("获取价格极值失败: " + e.getMessage());
        }
    }

    @Override
    public PriceBreakoutAnalysis analyzePriceBreakout(String symbol, String interval, int days) {
        try {
            // 计算时间范围：从当前日期往前推
            LocalDateTime now = LocalDateTime.now()
                .withHour(8).withMinute(0).withSecond(0).withNano(0);  // 调整到早上8点
            
            // 计算结束时间和开始时间
            LocalDateTime endTime = now.withDayOfMonth(15);    // 本月15号
            LocalDateTime startTime = now.withDayOfMonth(1);   // 本月1号
            
            // 获取历史K线数据
            List<KlineData> klineDataList = getHistoricalKlineData(symbol, interval, startTime, endTime, null);
            
            if (klineDataList.isEmpty()) {
                throw new MarketDataException("未获取到K线数据");
            }
            
            // 获取昨日收盘价（最后一根K线的收盘价）
            KlineData lastKline = klineDataList.get(klineDataList.size() - 1);
            BigDecimal lastClosePrice = new BigDecimal(lastKline.getClose());
            
            // 计算价格极值
            BigDecimal highPrice = BigDecimal.ZERO;
            BigDecimal lowPrice = new BigDecimal("999999999");
            LocalDateTime highTime = null;
            LocalDateTime lowTime = null;
            
            // 遍历K线数据找出最高价和最低价（不包括最后一根K线）
            for (int i = 0; i < klineDataList.size() - 1; i++) {
                KlineData kline = klineDataList.get(i);
                BigDecimal high = new BigDecimal(kline.getHigh());
                BigDecimal low = new BigDecimal(kline.getLow());
                
                if (high.compareTo(highPrice) > 0) {
                    highPrice = high;
                    highTime = LocalDateTime.ofInstant(
                        java.time.Instant.ofEpochMilli(kline.getOpenTime()), 
                        ZoneId.systemDefault()
                    );
                }
                
                if (low.compareTo(lowPrice) < 0) {
                    lowPrice = low;
                    lowTime = LocalDateTime.ofInstant(
                        java.time.Instant.ofEpochMilli(kline.getOpenTime()), 
                        ZoneId.systemDefault()
                    );
                }
            }
            
            // 计算波动幅度
            BigDecimal fluctuationRate = highPrice.subtract(lowPrice)
                .divide(lowPrice, 4, RoundingMode.HALF_UP)
                .multiply(new BigDecimal("100"));
            
            // 判断是否超过5%
            boolean exceeds5Percent = fluctuationRate.compareTo(new BigDecimal("5")) >= 0;
            
            // 分析价格位置
            String pricePosition;
            if (lastClosePrice.compareTo(highPrice) > 0) {
                pricePosition = String.format("当前价格 %s 高于区间最高点 %s，形成突破上涨",
                    lastClosePrice, highPrice);
            } else if (lastClosePrice.compareTo(lowPrice) < 0) {
                pricePosition = String.format("当前价格 %s 低于区间最低点 %s，形成突破下跌",
                    lastClosePrice, lowPrice);
            } else {
                BigDecimal range = highPrice.subtract(lowPrice);
                BigDecimal position = lastClosePrice.subtract(lowPrice)
                    .divide(range, 4, RoundingMode.HALF_UP)
                    .multiply(new BigDecimal("100"));
                pricePosition = String.format("当前价格 %s 位于区间内 %.2f%% 位置",
                    lastClosePrice, position);
            }
            
            boolean 突破最高价 = lastClosePrice.compareTo(highPrice) > 0;
            boolean 跌破最低价 = lastClosePrice.compareTo(lowPrice) < 0;
            String 突破状态;

            if (突破最高价) {
                突破状态 = "突破上涨";
            } else if (跌破最低价) {
                突破状态 = "突破下跌";
            } else {
                突破状态 = "区间内运行";
            }
            
            // 使用新的模型返回结果
            return PriceBreakoutAnalysis.builder()
                .分析时间范围(String.format("%s 到 %s", 
                    startTime.format(DATE_FORMATTER),
                    endTime.format(DATE_FORMATTER)))
                .区间最低价(lowPrice.toString())
                .区间最高价(highPrice.toString())
                .最低价出现时间(lowTime != null ? lowTime.format(DATE_FORMATTER) : null)
                .最高价出现时间(highTime != null ? highTime.format(DATE_FORMATTER) : null)
                .当前价格(lastClosePrice.toString())
                .价格位置(pricePosition)
                .波动幅度(String.format("%.2f%%", fluctuationRate))
                .波动超过5Percent(exceeds5Percent)
                .突破最高价(突破最高价)
                .跌破最低价(跌破最低价)
                .突破状态(突破状态)
                .build();
            
        } catch (Exception e) {
            log.error("分析价格突破失败: symbol={}, interval={}, days={}", symbol, interval, days, e);
            throw new MarketDataException("分析价格突破失败: " + e.getMessage());
        }
    }
} 